19
19
*/
20
20
package org .sonar .python .index ;
21
21
22
+ import java .util .Collections ;
22
23
import java .util .List ;
24
+ import java .util .Map ;
23
25
import java .util .Objects ;
24
26
import java .util .Set ;
25
27
import java .util .stream .Collectors ;
28
30
import org .sonar .plugins .python .api .symbols .ClassSymbol ;
29
31
import org .sonar .plugins .python .api .symbols .FunctionSymbol ;
30
32
import org .sonar .plugins .python .api .symbols .Symbol ;
33
+ import org .sonar .plugins .python .api .types .InferredType ;
31
34
import org .sonar .python .semantic .AmbiguousSymbolImpl ;
32
35
import org .sonar .python .semantic .ClassSymbolImpl ;
33
36
import org .sonar .python .semantic .FunctionSymbolImpl ;
34
37
import org .sonar .python .semantic .ProjectLevelSymbolTable ;
35
38
import org .sonar .python .semantic .SymbolImpl ;
39
+ import org .sonar .python .types .DeclaredType ;
40
+
41
+ import static org .sonar .python .semantic .SymbolUtils .typeshedSymbolWithFQN ;
42
+ import static org .sonar .python .types .InferredTypes .anyType ;
36
43
37
44
public class DescriptorUtils {
38
45
@@ -88,7 +95,7 @@ private static AmbiguousDescriptor ambiguousDescriptor(AmbiguousSymbol ambiguous
88
95
}
89
96
90
97
public static AmbiguousDescriptor ambiguousDescriptor (AmbiguousSymbol ambiguousSymbol , @ Nullable String overriddenFQN ) {
91
- String fullyQualifiedName = overriddenFQN != null ? overriddenFQN : ambiguousSymbol .fullyQualifiedName ();
98
+ String fullyQualifiedName = overriddenFQN != null ? overriddenFQN : ambiguousSymbol .fullyQualifiedName ();
92
99
Set <Descriptor > alternatives = ambiguousSymbol .alternatives ().stream ()
93
100
.map (DescriptorUtils ::descriptor )
94
101
.collect (Collectors .toSet ());
@@ -107,27 +114,89 @@ private static List<FunctionDescriptor.Parameter> parameters(List<FunctionSymbol
107
114
)).collect (Collectors .toList ());
108
115
}
109
116
110
- public static Symbol symbolFromDescriptor (Descriptor descriptor , ProjectLevelSymbolTable projectLevelSymbolTable ) {
111
- return symbolFromDescriptor (descriptor , projectLevelSymbolTable , null );
112
- }
113
-
114
- public static Symbol symbolFromDescriptor (Descriptor descriptor , ProjectLevelSymbolTable projectLevelSymbolTable , @ Nullable String localSymbolName ) {
117
+ public static Symbol symbolFromDescriptor (Descriptor descriptor , ProjectLevelSymbolTable projectLevelSymbolTable ,
118
+ @ Nullable String localSymbolName , Map <String , Symbol > createdSymbols ) {
115
119
// The symbol generated from the descriptor will not have the descriptor name if an alias (localSymbolName) is defined
120
+ if (createdSymbols .containsKey (descriptor .fullyQualifiedName ())) {
121
+ return createdSymbols .get (descriptor .fullyQualifiedName ());
122
+ }
116
123
String symbolName = localSymbolName != null ? localSymbolName : descriptor .name ();
117
124
switch (descriptor .kind ()) {
118
125
case CLASS :
119
- return new ClassSymbolImpl (( ClassDescriptor ) descriptor , projectLevelSymbolTable , symbolName );
126
+ return createClassSymbol ( descriptor , projectLevelSymbolTable , createdSymbols , symbolName );
120
127
case FUNCTION :
121
- return new FunctionSymbolImpl ((FunctionDescriptor ) descriptor , projectLevelSymbolTable , symbolName );
128
+ return createFunctionSymbol ((FunctionDescriptor ) descriptor , projectLevelSymbolTable , createdSymbols , symbolName );
122
129
case VARIABLE :
123
130
return new SymbolImpl (symbolName , descriptor .fullyQualifiedName ());
124
131
case AMBIGUOUS :
125
132
Set <Symbol > alternatives = ((AmbiguousDescriptor ) descriptor ).alternatives ().stream ()
126
- .map (a -> DescriptorUtils .symbolFromDescriptor (a , projectLevelSymbolTable , symbolName ))
133
+ .map (a -> DescriptorUtils .symbolFromDescriptor (a , projectLevelSymbolTable , symbolName , createdSymbols ))
127
134
.collect (Collectors .toSet ());
128
135
return new AmbiguousSymbolImpl (symbolName , descriptor .fullyQualifiedName (), alternatives );
129
136
default :
130
137
throw new IllegalStateException (String .format ("Error while creating a Symbol from a Descriptor: Unexpected descriptor kind: %s" , descriptor .kind ()));
131
138
}
132
139
}
140
+
141
+ private static ClassSymbolImpl createClassSymbol (Descriptor descriptor , ProjectLevelSymbolTable projectLevelSymbolTable , Map <String , Symbol > createdSymbols , String symbolName ) {
142
+ ClassDescriptor classDescriptor = (ClassDescriptor ) descriptor ;
143
+ ClassSymbolImpl classSymbol = new ClassSymbolImpl ((ClassDescriptor ) descriptor , symbolName );
144
+ createdSymbols .put (descriptor .fullyQualifiedName (), classSymbol );
145
+ addSuperClasses (classSymbol , classDescriptor , projectLevelSymbolTable , createdSymbols );
146
+ addMembers (classSymbol , classDescriptor , projectLevelSymbolTable , createdSymbols );
147
+ return classSymbol ;
148
+ }
149
+
150
+ private static void addMembers (ClassSymbolImpl classSymbol , ClassDescriptor classDescriptor ,
151
+ ProjectLevelSymbolTable projectLevelSymbolTable , Map <String , Symbol > createdSymbols ) {
152
+ classSymbol .addMembers (classDescriptor .members ().stream ()
153
+ .map (memberFqn -> DescriptorUtils .symbolFromDescriptor (memberFqn , projectLevelSymbolTable , null , createdSymbols ))
154
+ .map (member -> {
155
+ if (member instanceof FunctionSymbolImpl ) {
156
+ ((FunctionSymbolImpl ) member ).setOwner (classSymbol );
157
+ }
158
+ return member ;
159
+ })
160
+ .collect (Collectors .toList ()));
161
+ }
162
+
163
+ private static void addSuperClasses (ClassSymbolImpl classSymbol , ClassDescriptor classDescriptor ,
164
+ ProjectLevelSymbolTable projectLevelSymbolTable , Map <String , Symbol > createdSymbols ) {
165
+ classDescriptor .superClasses ().stream ()
166
+ .map (superClassFqn -> {
167
+ if (createdSymbols .containsKey (superClassFqn )) {
168
+ return createdSymbols .get (superClassFqn );
169
+ }
170
+ Symbol symbol = projectLevelSymbolTable .getSymbol (superClassFqn );
171
+ symbol = symbol != null ? symbol : typeshedSymbolWithFQN (superClassFqn );
172
+ createdSymbols .put (superClassFqn , symbol );
173
+ return symbol ;
174
+ }
175
+ )
176
+ .forEach (classSymbol ::addSuperClass );
177
+ }
178
+
179
+ private static FunctionSymbolImpl createFunctionSymbol (FunctionDescriptor functionDescriptor , ProjectLevelSymbolTable projectLevelSymbolTable ,
180
+ Map <String , Symbol > createdSymbols , String symbolName ) {
181
+ FunctionSymbolImpl functionSymbol = new FunctionSymbolImpl (functionDescriptor , symbolName );
182
+ addParameters (functionSymbol , functionDescriptor , projectLevelSymbolTable , createdSymbols );
183
+ return functionSymbol ;
184
+ }
185
+
186
+ private static void addParameters (FunctionSymbolImpl functionSymbol , FunctionDescriptor functionDescriptor ,
187
+ ProjectLevelSymbolTable projectLevelSymbolTable , Map <String , Symbol > createdSymbols ) {
188
+ functionDescriptor .parameters ().stream ().map (p -> {
189
+ FunctionSymbolImpl .ParameterImpl parameter = new FunctionSymbolImpl .ParameterImpl (p );
190
+ Symbol existingSymbol = createdSymbols .get (p .annotatedType ());
191
+ Symbol typeSymbol = existingSymbol != null ? existingSymbol : projectLevelSymbolTable .getSymbol (p .annotatedType ());
192
+ String annotatedTypeName = parameter .annotatedTypeName ();
193
+ if (typeSymbol == null && annotatedTypeName != null ) {
194
+ typeSymbol = typeshedSymbolWithFQN (annotatedTypeName );
195
+ }
196
+ // TODO: SONARPY-951 starred parameters should be mapped to the appropriate runtime type
197
+ InferredType declaredType = typeSymbol == null ? anyType () : new DeclaredType (typeSymbol , Collections .emptyList ());
198
+ parameter .setDeclaredType (declaredType );
199
+ return parameter ;
200
+ }).forEach (functionSymbol ::addParameter );
201
+ }
133
202
}
0 commit comments