Skip to content

Commit f21f5d9

Browse files
committed
Add function call diagramm
1 parent 714d8d4 commit f21f5d9

8 files changed

Lines changed: 472 additions & 34 deletions

File tree

‎plugins/csharp/parser/src_csharp/AstVisitor.cs‎

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,35 @@ private ulong fnvHash(string data_)
5656
}
5757

5858
return hash;
59-
}
59+
}
60+
61+
// Deterministic replacement for GetHashCode(), which is reference based
62+
// for syntax nodes and randomized per process for strings. Both would
63+
// give different ids for the same entity on every parse.
64+
private long stableHash(string data_)
65+
{
66+
return unchecked((long)fnvHash(data_));
67+
}
68+
69+
private long getEntityHash(SyntaxNode node)
70+
{
71+
string[] properties =
72+
{
73+
node.SyntaxTree.FilePath,":",
74+
node.Kind().ToString(),":",
75+
node.Span.Start.ToString(),":",
76+
node.Span.End.ToString()
77+
};
78+
79+
return stableHash(string.Concat(properties));
80+
}
6081

6182
private ulong getAstNodeId(SyntaxNode node){
6283
CsharpAstNode astNode = new CsharpAstNode
6384
{
6485
AstValue = node.ToString(),
6586
RawKind = node.Kind(),
66-
EntityHash = node.GetHashCode(),
87+
EntityHash = getEntityHash(node),
6788
AstType = AstTypeEnum.Declaration
6889
};
6990
astNode.SetLocation(node.SyntaxTree.GetLineSpan(node.Span));
@@ -86,7 +107,7 @@ private CsharpAstNode AstNode(SyntaxNode node, AstSymbolTypeEnum type, AstTypeEn
86107
{
87108
AstValue = node.ToString(),
88109
RawKind = node.Kind(),
89-
EntityHash = node.GetHashCode(),
110+
EntityHash = getEntityHash(node),
90111
AstSymbolType = type,
91112
AstType = astType,
92113
Accessibility = acc
@@ -616,7 +637,7 @@ private void VisitMethodDecl(MethodDeclarationSyntax node, CsharpAstNode parent)
616637
QualifiedName = qName,
617638
QualifiedType = qType,
618639
DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(),
619-
TypeHash = qType.GetHashCode(),
640+
TypeHash = stableHash(qType),
620641
EntityHash = astNode.EntityHash,
621642
ParentNode = parent,
622643
MethodType = MethodTypeEnum.Method
@@ -666,7 +687,7 @@ private void VisitOperatorDecl(OperatorDeclarationSyntax node, CsharpAstNode par
666687
QualifiedName = qName,
667688
QualifiedType = qType,
668689
DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(),
669-
TypeHash = qType.GetHashCode(),
690+
TypeHash = stableHash(qType),
670691
EntityHash = astNode.EntityHash,
671692
ParentNode = parent,
672693
MethodType = MethodTypeEnum.Operator
@@ -704,7 +725,7 @@ private void VisitMethodParameters(SeparatedSyntaxList<ParameterSyntax> paramete
704725
AstNode = astNode,
705726
Name = param.Identifier.Text,
706727
QualifiedType = paramQType,
707-
TypeHash = paramQType.GetHashCode(),
728+
TypeHash = stableHash(paramQType),
708729
EntityHash = astNode.EntityHash,
709730
ParentNode = parent,
710731
VariableType = VariableTypeEnum.Parameter
@@ -752,7 +773,7 @@ private void VisitVariableDecl(VariableDeclarationSyntax node, CsharpAstNode par
752773
AstNode = astNode,
753774
Name = variable.Identifier.Text,
754775
QualifiedType = varQType,
755-
TypeHash = varQType.GetHashCode(),
776+
TypeHash = stableHash(varQType),
756777
DocumentationCommentXML = Model.GetDeclaredSymbol(variable).GetDocumentationCommentXml(),
757778
EntityHash = astNode.EntityHash,
758779
VariableType = isLINQvar ? VariableTypeEnum.LINQ : VariableTypeEnum.Variable,
@@ -779,7 +800,7 @@ private void VisitPropertyDecl(PropertyDeclarationSyntax node, CsharpAstNode par
779800
AstNode = astNode,
780801
Name = node.Identifier.Text,
781802
QualifiedType = varQType,
782-
TypeHash = varQType.GetHashCode(),
803+
TypeHash = stableHash(varQType),
783804
VariableType = VariableTypeEnum.Property,
784805
DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(),
785806
EntityHash = astNode.EntityHash,
@@ -951,11 +972,69 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node)
951972
DbContext.CsharpEtcEntitys.Add(invoc);
952973
}
953974
}
954-
}
955-
}
975+
}
976+
}
977+
978+
VisitMethodInvocation(node);
956979

957980
base.VisitInvocationExpression(node);
958-
}
981+
}
982+
983+
// Records an invocation whose DeclaratorNodeId points to the declaration
984+
// of the called method. This is what the Callee / Caller references and
985+
// the function call diagram rely on.
986+
private void VisitMethodInvocation(InvocationExpressionSyntax node)
987+
{
988+
SimpleNameSyntax name = node.Expression switch
989+
{
990+
MemberAccessExpressionSyntax memberAccess => memberAccess.Name,
991+
MemberBindingExpressionSyntax memberBinding => memberBinding.Name,
992+
SimpleNameSyntax simpleName => simpleName,
993+
_ => null
994+
};
995+
996+
// Unqualified Foo() calls are already recorded by VisitIdentifierName.
997+
if (name == null || (name == node.Expression && name is IdentifierNameSyntax))
998+
return;
999+
1000+
var method = Model.GetSymbolInfo(node).Symbol as IMethodSymbol;
1001+
if (method == null)
1002+
return;
1003+
1004+
method = (method.ReducedFrom ?? method).OriginalDefinition;
1005+
method = method.PartialImplementationPart ?? method;
1006+
1007+
var declaration = method.DeclaringSyntaxReferences
1008+
.Select(r => r.GetSyntax())
1009+
.FirstOrDefault(s => s is BaseMethodDeclarationSyntax);
1010+
if (declaration == null)
1011+
return;
1012+
1013+
var type = "";
1014+
try
1015+
{
1016+
var info = Model.GetTypeInfo(node).ConvertedType;
1017+
if (info != null) type = info.Name;
1018+
}
1019+
catch (Exception)
1020+
{
1021+
FullyParsed = false;
1022+
}
1023+
1024+
var declaratorNodeId = getAstNodeId(declaration);
1025+
var astNode = AstNode(name, AstSymbolTypeEnum.EtcEntity, AstTypeEnum.Usage);
1026+
CsharpEtcEntity invoc = new CsharpEtcEntity
1027+
{
1028+
AstNode = astNode,
1029+
EntityHash = astNode.EntityHash,
1030+
EtcEntityType = EtcEntityTypeEnum.Invocation,
1031+
DeclaratorNodeId = declaratorNodeId,
1032+
Name = name.Identifier.Text,
1033+
QualifiedName = method.ToString(),
1034+
QualifiedType = type
1035+
};
1036+
DbContext.CsharpEtcEntitys.Add(invoc);
1037+
}
9591038

9601039
public override void VisitIdentifierName(IdentifierNameSyntax node)
9611040
{

‎plugins/csharp/service/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ add_subdirectory(src_csharp)
3939

4040
add_library(csharpservice SHARED
4141
src/csharpservice.cpp
42+
src/csharpdiagram.cpp
4243
src/plugin.cpp)
4344

4445
target_compile_options(csharpservice PUBLIC -Wno-unknown-pragmas)

‎plugins/csharp/service/csharpservice.thrift‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ service CsharpService
4949
map<string, i32> getDiagramTypes(1:common.AstNodeId astNodeId)
5050
throws (1:common.InvalidId ex)
5151

52-
string getDiagram(1:common.AstNodeId astNodeId, 2:i32 diagramId)
53-
throws (1:common.InvalidId exId, 2:common.Timeout exLong)
54-
5552
list<language.SyntaxHighlight> getSyntaxHighlight(
5653
1:common.FileRange range,
5754
2:list<string> content)

‎plugins/csharp/service/include/service/csharpservice.h‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,6 @@ class CSharpQueryHandler : public CsharpServiceIf
184184
_service -> getDiagramTypes(return_, astNodeId_);
185185
}
186186

187-
void getDiagram(
188-
std::string& return_,
189-
const core::AstNodeId& astNodeId_,
190-
const std::int32_t diagramId_) override
191-
{
192-
_service -> getDiagram(return_, astNodeId_, diagramId_);
193-
}
194-
195187
void getSyntaxHighlight(
196188
std::vector<language::SyntaxHighlight>& return_,
197189
const core::FileRange& range_,
@@ -219,7 +211,7 @@ using TransportException = apache::thrift::transport::TTransportException;
219211

220212
class CsharpServiceHandler : virtual public LanguageServiceIf
221213
{
222-
friend class Diagram;
214+
friend class CsharpDiagram;
223215

224216
public:
225217
CsharpServiceHandler(
@@ -323,6 +315,18 @@ class CsharpServiceHandler : virtual public LanguageServiceIf
323315
const core::FileRange& range_) override;
324316

325317
private:
318+
// Must be kept in sync with CSharpServiceEnums.cs.
319+
enum DiagramType
320+
{
321+
FUNCTION_CALL
322+
};
323+
324+
enum ReferenceType
325+
{
326+
CALLEE = 5,
327+
CALLER = 6
328+
};
329+
326330
std::shared_ptr<odb::database> _db;
327331
util::OdbTransaction _transaction;
328332

0 commit comments

Comments
 (0)