Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit a502cb5

Browse files
author
MikhailArkhipov
committed
Merge master
2 parents da3eb70 + bede6cc commit a502cb5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1417
-271
lines changed

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Constants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public IPythonInstance GetConstantFromLiteral(Expression expr, LookupOptions opt
3232
return new PythonAsciiString(b, Interpreter);
3333
case int integer:
3434
return new PythonConstant(integer, Interpreter.GetBuiltinType(BuiltinTypeId.Int));
35+
case bool b:
36+
return new PythonConstant(b, Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
3537
}
3638
}
3739

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private bool GenericClassParameterValid(IReadOnlyList<IGenericTypeDefinition> ge
7272
Resources.GenericNotAllTypeParameters,
7373
GetLocation(expr).Span,
7474
ErrorCodes.TypingGenericArguments,
75-
Severity.Error,
75+
Severity.Warning,
7676
DiagnosticSource.Analysis));
7777
return false;
7878
}
@@ -83,7 +83,7 @@ private bool GenericClassParameterValid(IReadOnlyList<IGenericTypeDefinition> ge
8383
Resources.GenericNotAllUnique,
8484
GetLocation(expr).Span,
8585
ErrorCodes.TypingGenericArguments,
86-
Severity.Error,
86+
Severity.Warning,
8787
DiagnosticSource.Analysis));
8888
return false;
8989
}

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@
1313
// See the Apache Version 2.0 License for specific language governing
1414
// permissions and limitations under the License.
1515

16-
using Microsoft.Python.Analysis.Diagnostics;
1716
using Microsoft.Python.Analysis.Modules;
1817
using Microsoft.Python.Analysis.Types;
1918
using Microsoft.Python.Analysis.Types.Collections;
2019
using Microsoft.Python.Analysis.Values;
21-
using Microsoft.Python.Core;
2220
using Microsoft.Python.Parsing;
2321
using Microsoft.Python.Parsing.Ast;
24-
using ErrorCodes = Microsoft.Python.Analysis.Diagnostics.ErrorCodes;
2522

2623
namespace Microsoft.Python.Analysis.Analyzer.Evaluation {
2724
internal sealed partial class ExpressionEval {
@@ -124,9 +121,6 @@ private IMember GetValueFromBinaryOp(Expression expr) {
124121

125122
if (leftIsSupported && rightIsSupported) {
126123
if (TryGetValueFromBuiltinBinaryOp(op, leftTypeId, rightTypeId, Interpreter.LanguageVersion.Is3x(), out var member)) {
127-
if (member.IsUnknown()) {
128-
ReportOperatorDiagnostics(expr, leftType, rightType, op);
129-
}
130124
return member;
131125
}
132126
}
@@ -440,14 +434,5 @@ private static (string name, string swappedName) OpMethodName(PythonOperator op)
440434

441435
return (null, null);
442436
}
443-
private void ReportOperatorDiagnostics(Expression expr, IPythonType leftType, IPythonType rightType, PythonOperator op) {
444-
ReportDiagnostics(Module.Uri, new DiagnosticsEntry(
445-
Resources.UnsupporedOperandType.FormatInvariant(op.ToCodeString(), leftType.Name, rightType.Name),
446-
GetLocation(expr).Span,
447-
ErrorCodes.UnsupportedOperandType,
448-
Severity.Error,
449-
DiagnosticSource.Analysis));
450-
}
451-
452437
}
453438
}

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using Microsoft.Python.Analysis.Diagnostics;
2121
using Microsoft.Python.Analysis.Modules;
2222
using Microsoft.Python.Analysis.Types;
23-
using Microsoft.Python.Analysis.Utilities;
2423
using Microsoft.Python.Analysis.Values;
2524
using Microsoft.Python.Core;
2625
using Microsoft.Python.Core.Disposables;
@@ -106,7 +105,7 @@ public Location GetLocationOfName(Node node) {
106105

107106
public void ReportDiagnostics(Uri documentUri, DiagnosticsEntry entry) {
108107
// Do not add if module is library, etc. Only handle user code.
109-
if (Module.ModuleType == ModuleType.User) {
108+
if (entry.ShouldReport(Module)) {
110109
lock (_lock) {
111110
_diagnostics.Add(entry);
112111
}

src/Analysis/Ast/Impl/Analyzer/Handlers/WithHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void HandleWith(WithStatement node) {
3535
// If fetching context from __enter__ failed, annotation in the stub may be using
3636
// type from typing that we haven't specialized yet or there may be an issue in
3737
// the stub itself, such as type or incorrect type. Try using context manager then.
38-
context = context ?? contextManager;
38+
context = context.IsUnknown() ? contextManager : context;
3939
}
4040

4141
if (item.Variable is NameExpression nex && !string.IsNullOrEmpty(nex.Name)) {

src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public IReadOnlyList<DiagnosticsEntry> LintModule(IPythonModule module) {
192192
// Linter always runs no matter of the option since it looks up variables
193193
// which also enumerates and updates variable references for find all
194194
// references and rename operations.
195-
var result = new LinterAggregator().Lint(module.Analysis, _services);
195+
var result = new LinterAggregator().Lint(module, _services);
196196

197197
var optionsProvider = _services.GetService<IAnalysisOptionsProvider>();
198198
return optionsProvider?.Options?.LintingEnabled == false ? Array.Empty<DiagnosticsEntry>() : result;

src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerEntry.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public IDocumentAnalysis PreviousAnalysis {
7777
}
7878
}
7979
}
80-
80+
8181
public int BufferVersion => _bufferVersion;
8282

8383
public int AnalysisVersion {
@@ -89,7 +89,7 @@ public int AnalysisVersion {
8989
}
9090

9191
public bool NotAnalyzed => PreviousAnalysis is EmptyAnalysis;
92-
92+
9393
public PythonAnalyzerEntry(EmptyAnalysis emptyAnalysis) {
9494
_previousAnalysis = emptyAnalysis;
9595
_module = emptyAnalysis.Document;
@@ -100,7 +100,7 @@ public PythonAnalyzerEntry(EmptyAnalysis emptyAnalysis) {
100100
_analysisTcs = new TaskCompletionSource<IDocumentAnalysis>(TaskCreationOptions.RunContinuationsAsynchronously);
101101
}
102102

103-
public Task<IDocumentAnalysis> GetAnalysisAsync(CancellationToken cancellationToken)
103+
public Task<IDocumentAnalysis> GetAnalysisAsync(CancellationToken cancellationToken)
104104
=> _analysisTcs.Task.ContinueWith(t => t.GetAwaiter().GetResult(), cancellationToken);
105105

106106
public bool IsValidVersion(int version, out IPythonModule module, out PythonAst ast) {
@@ -164,7 +164,7 @@ public void TryCancel(OperationCanceledException oce, int version) {
164164

165165
_analysisVersion = version;
166166
}
167-
167+
168168
_analysisTcs.TrySetCanceled(oce.CancellationToken);
169169
}
170170

@@ -244,7 +244,7 @@ public bool Invalidate(IPythonModule module, PythonAst ast, int bufferVersion, i
244244

245245
Interlocked.Exchange(ref _bufferVersion, bufferVersion);
246246
UpdateAnalysisTcs(analysisVersion);
247-
dependencies = _analysisDependencies != null
247+
dependencies = _analysisDependencies != null
248248
? ImmutableArray<AnalysisModuleKey>.Create(_parserDependencies.Union(_analysisDependencies).ToArray())
249249
: ImmutableArray<AnalysisModuleKey>.Create(_parserDependencies);
250250
return true;
@@ -270,7 +270,6 @@ private void UpdateAnalysisTcs(int analysisVersion) {
270270
_analysisVersion = analysisVersion;
271271
if (_analysisTcs.Task.Status == TaskStatus.RanToCompletion) {
272272
_previousAnalysis = _analysisTcs.Task.Result;
273-
_analysisDependencies = null;
274273
}
275274

276275
if (_analysisTcs.Task.IsCompleted) {

src/Analysis/Ast/Impl/Analyzer/Symbols/ClassEvaluator.cs

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Linq;
1919
using Microsoft.Python.Analysis.Analyzer.Evaluation;
2020
using Microsoft.Python.Analysis.Diagnostics;
21+
using Microsoft.Python.Analysis.Specializations.Typing;
2122
using Microsoft.Python.Analysis.Types;
2223
using Microsoft.Python.Analysis.Values;
2324
using Microsoft.Python.Core;
@@ -51,21 +52,10 @@ public void EvaluateClass() {
5152

5253
// Evaluate inner classes, if any
5354
EvaluateInnerClasses(_classDef);
54-
5555
_class = classInfo;
56-
// Set bases to the class.
57-
var bases = new List<IPythonType>();
58-
foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name))) {
59-
// We cheat slightly and treat base classes as annotations.
60-
var b = Eval.GetTypeFromAnnotation(a.Expression);
61-
if (b != null) {
62-
var t = b.GetPythonType();
63-
bases.Add(t);
64-
t.AddReference(Eval.GetLocationOfName(a.Expression));
65-
}
66-
}
67-
_class.SetBases(bases);
6856

57+
var bases = ProcessBases();
58+
_class.SetBases(bases);
6959
// Declare __class__ variable in the scope.
7060
Eval.DeclareVariable("__class__", _class, VariableSource.Declaration);
7161
ProcessClassBody();
@@ -120,6 +110,59 @@ private void ProcessClassBody() {
120110
UpdateClassMembers();
121111
}
122112

113+
private IEnumerable<IPythonType> ProcessBases() {
114+
var bases = new List<IPythonType>();
115+
foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name))) {
116+
if (IsValidBase(a)) {
117+
TryAddBase(bases, a);
118+
} else {
119+
ReportInvalidBase(a.ToCodeString(Eval.Ast, CodeFormattingOptions.Traditional));
120+
}
121+
}
122+
123+
return bases;
124+
}
125+
126+
private bool IsValidBase(Arg a) {
127+
var expr = a.Expression;
128+
var m = Eval.GetValueFromExpression(expr);
129+
130+
// Allow any unknown members
131+
if (m.IsUnknown()) {
132+
return true;
133+
}
134+
135+
// Allow extensions from specialized functions
136+
// We specialized type to be a function even though it is a class, so this allows extension of type
137+
// TODO handle module specialization better: https://github.com/microsoft/python-language-server/issues/1367
138+
if (m is IPythonType t && t.IsSpecialized) {
139+
return true;
140+
}
141+
142+
switch (m.MemberType) {
143+
// Inheriting from these members is invalid
144+
case PythonMemberType.Method:
145+
case PythonMemberType.Function:
146+
case PythonMemberType.Property:
147+
case PythonMemberType.Instance:
148+
case PythonMemberType.Variable when m is IPythonConstant:
149+
return false;
150+
}
151+
152+
// Optimistically say anything that passes these checks is a valid base
153+
return true;
154+
}
155+
156+
private void TryAddBase(List<IPythonType> bases, Arg arg) {
157+
// We cheat slightly and treat base classes as annotations.
158+
var b = Eval.GetTypeFromAnnotation(arg.Expression);
159+
if (b != null) {
160+
var t = b.GetPythonType();
161+
bases.Add(t);
162+
t.AddReference(Eval.GetLocationOfName(arg.Expression));
163+
}
164+
}
165+
123166
private void EvaluateConstructors(ClassDefinition cd) {
124167
// Do not use foreach since walker list is dynamically modified and walkers are removed
125168
// after processing. Handle __init__ and __new__ first so class variables are initialized.
@@ -154,6 +197,17 @@ private void UpdateClassMembers() {
154197
_class.AddMembers(members, false);
155198
}
156199

200+
private void ReportInvalidBase(string argVal) {
201+
Eval.ReportDiagnostics(Eval.Module.Uri,
202+
new DiagnosticsEntry(
203+
Resources.InheritNonClass.FormatInvariant(argVal),
204+
_classDef.NameExpression.GetLocation(Eval)?.Span ?? default,
205+
Diagnostics.ErrorCodes.InheritNonClass,
206+
Severity.Warning,
207+
DiagnosticSource.Analysis
208+
));
209+
}
210+
157211
// Classes and functions are walked by their respective evaluators
158212
public override bool Walk(ClassDefinition node) => false;
159213
public override bool Walk(FunctionDefinition node) => false;

src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System.Collections.Generic;
1818
using System.Linq;
1919
using Microsoft.Python.Analysis.Analyzer.Evaluation;
20+
using Microsoft.Python.Analysis.Diagnostics;
2021
using Microsoft.Python.Analysis.Types;
2122
using Microsoft.Python.Analysis.Values;
2223
using Microsoft.Python.Core;

src/Analysis/Ast/Impl/Diagnostics/DiagnosticsEntry.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// See the Apache Version 2.0 License for specific language governing
1414
// permissions and limitations under the License.
1515

16+
using Microsoft.Python.Analysis.Modules;
17+
using Microsoft.Python.Analysis.Types;
18+
using Microsoft.Python.Core;
1619
using Microsoft.Python.Core.Text;
1720
using Microsoft.Python.Parsing;
1821

@@ -51,6 +54,20 @@ public DiagnosticsEntry(string message, SourceSpan span, string errorCode, Sever
5154
/// </summary>
5255
public DiagnosticSource Source { get; }
5356

57+
public bool ShouldReport(IPythonModule module) {
58+
// Only report for user written modules
59+
if (module.ModuleType != ModuleType.User) {
60+
return false;
61+
}
62+
63+
// If user specifies #noqa, then do not report diagnostic
64+
if (module.GetComment(SourceSpan.Start.Line).EqualsIgnoreCase("noqa")) {
65+
return false;
66+
}
67+
68+
return true;
69+
}
70+
5471
public override bool Equals(object obj) {
5572
if (!(obj is DiagnosticsEntry e)) {
5673
return false;

0 commit comments

Comments
 (0)