use of org.python.pydev.ast.analysis.messages.IMessage in project Pydev by fabioz.
the class AnalysisBuilderRunnable method doAnalysis.
@Override
protected void doAnalysis() {
if (!nature.startRequests()) {
return;
}
try {
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "doAnalysis() - " + moduleName + " " + this.getAnalysisCauseStr());
}
// if the resource is not open, there's not much we can do...
final IResource r = resource;
if (r == null) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Finished analysis -- resource null -- " + moduleName);
return;
}
if (!r.getProject().isOpen()) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Finished analysis -- project closed -- " + moduleName);
return;
}
AnalysisRunner runner = new AnalysisRunner();
checkStop();
IAnalysisPreferences analysisPreferences = new AnalysisPreferences(r);
boolean makeAnalysis = // just get problems in resources that are in the pythonpath
runner.canDoAnalysis(document) && PyDevBuilderVisitor.isInPythonPath(r) && analysisPreferences.makeCodeAnalysis();
boolean anotherVisitorRequiresAnalysis = false;
for (IExternalCodeAnalysisVisitor visitor : allVisitors) {
anotherVisitorRequiresAnalysis |= visitor.getRequiresAnalysis();
}
if (!makeAnalysis) {
// let's see if we should do code analysis
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Skipping: !makeAnalysis -- " + moduleName);
}
if (!anotherVisitorRequiresAnalysis) {
AnalysisRunner.deleteMarkers(r);
return;
} else {
// Only delete pydev markers (others will be deleted by the respective visitors later on).
boolean onlyPydevAnalysisMarkers = true;
AnalysisRunner.deleteMarkers(r, onlyPydevAnalysisMarkers);
}
}
if (makeAnalysis && onlyRecreateCtxInsensitiveInfo) {
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Skipping: !forceAnalysis && analysisCause == ANALYSIS_CAUSE_BUILDER && " + "PyDevBuilderPrefPage.getAnalyzeOnlyActiveEditor() -- " + moduleName);
}
return;
}
if (nature == null) {
Log.log("Finished analysis: null nature -- " + moduleName);
return;
}
AbstractAdditionalTokensInfo info = AdditionalProjectInterpreterInfo.getAdditionalInfoForProject(nature);
if (info == null) {
Log.log("Unable to get additional info for: " + r + " -- " + moduleName);
return;
}
if (makeAnalysis && DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "makeAnalysis:" + makeAnalysis + " " + "analysisCause: " + getAnalysisCauseStr() + " -- " + moduleName);
}
checkStop();
if (isHierarchicallyDerived(r)) {
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Resource marked as derived not analyzed: " + r + " -- " + moduleName);
}
// might be already there)
if (r != null) {
AnalysisRunner.deleteMarkers(r);
}
return;
}
// Maybe we can improve that when https://github.com/PyCQA/pylint/pull/1189 is done.
if (!DocumentChanged.hasDocumentChanged(resource, document)) {
for (IExternalCodeAnalysisVisitor visitor : allVisitors) {
visitor.startVisit();
}
} else {
for (IExternalCodeAnalysisVisitor visitor : allVisitors) {
visitor.deleteMarkers();
}
if (!makeAnalysis) {
return;
}
}
List<MarkerInfo> markersFromCodeAnalysis = null;
if (makeAnalysis) {
OccurrencesAnalyzer analyzer = new OccurrencesAnalyzer();
checkStop();
SourceModule module = (SourceModule) this.module.call(moduleRequest);
IMessage[] messages = analyzer.analyzeDocument(nature, module, analysisPreferences, document, this.internalCancelMonitor, DefaultIndentPrefs.get(this.resource));
checkStop();
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Adding markers for module: " + moduleName);
// for (IMessage message : messages) {
// Log.toLogFile(this, message.toString());
// }
}
// last chance to stop...
checkStop();
// don't stop after setting to add / remove the markers
if (r != null) {
boolean analyzeOnlyActiveEditor = PyDevBuilderPreferences.getAnalyzeOnlyActiveEditor();
if (forceAnalysis || !analyzeOnlyActiveEditor || (analyzeOnlyActiveEditor && (!PyDevBuilderPreferences.getRemoveErrorsWhenEditorIsClosed() || OpenEditors.isEditorOpenForResource(r)))) {
markersFromCodeAnalysis = runner.setMarkers(r, document, messages, this.internalCancelMonitor);
} else {
if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
org.python.pydev.shared_core.log.ToLogFile.toLogFile(this, "Skipped adding markers for module: " + moduleName + " (editor not opened).");
}
}
}
}
// if there are callbacks registered, call them if we still didn't return (mostly for tests)
for (ICallback<Object, IResource> callback : analysisBuilderListeners) {
try {
callback.call(r);
} catch (Exception e) {
Log.log(e);
}
}
checkStop();
for (IExternalCodeAnalysisVisitor visitor : allVisitors) {
visitor.join();
}
checkStop();
if (r != null) {
for (IExternalCodeAnalysisVisitor visitor : allVisitors) {
String problemMarker = visitor.getProblemMarkerId();
String messageId = visitor.getMessageId();
List<MarkerInfo> markersFromVisitor = visitor.getMarkers(resource);
if (markersFromVisitor != null && markersFromVisitor.size() > 0) {
Map<Integer, List<MarkerInfo>> lineToMarkerInfo = new HashMap<>();
if (markersFromCodeAnalysis != null) {
for (MarkerInfo codeAnalysisMarkerInfo : markersFromCodeAnalysis) {
List<MarkerInfo> list = lineToMarkerInfo.get(codeAnalysisMarkerInfo.lineStart);
if (list == null) {
list = new ArrayList<>(2);
lineToMarkerInfo.put(codeAnalysisMarkerInfo.lineStart, list);
}
list.add(codeAnalysisMarkerInfo);
}
}
if (visitor == pyLintVisitor) {
// (there's no real point in putting an error twice).
for (Iterator<MarkerInfo> visitorMarkerInfoIterator = markersFromVisitor.iterator(); visitorMarkerInfoIterator.hasNext(); ) {
MarkerInfo visitorMarkerInfo = visitorMarkerInfoIterator.next();
List<MarkerInfo> codeAnalysisMarkers = lineToMarkerInfo.get(visitorMarkerInfo.lineStart);
if (codeAnalysisMarkers != null && codeAnalysisMarkers.size() > 0) {
for (MarkerInfo codeAnalysisMarker : codeAnalysisMarkers) {
if (codeAnalysisMarker.severity < IMarker.SEVERITY_INFO) {
// Don't consider if it shouldn't be shown.
continue;
}
Map<String, Object> additionalInfo = codeAnalysisMarker.additionalInfo;
if (additionalInfo != null) {
Object analysisType = additionalInfo.get(AnalysisRunner.PYDEV_ANALYSIS_TYPE);
if (analysisType != null && analysisType instanceof Integer) {
String pyLintMessageId = CheckAnalysisErrors.getPyLintMessageIdForPyDevAnalysisType((int) analysisType);
if (pyLintMessageId != null && pyLintMessageId.equals(visitorMarkerInfo.additionalInfo.get(messageId))) {
visitorMarkerInfoIterator.remove();
// Stop the for (we've already removed it).
break;
}
}
}
}
}
}
}
PyMarkerUtils.replaceMarkers(markersFromVisitor, resource, problemMarker, true, this.internalCancelMonitor);
} else {
visitor.deleteMarkers();
}
}
}
} catch (OperationCanceledException e) {
// ok, ignore it
logOperationCancelled();
} catch (Exception e) {
Log.log(e);
} finally {
try {
nature.endRequests();
} catch (Throwable e) {
Log.log("Error when analyzing: " + moduleName, e);
}
try {
AnalysisBuilderRunnableFactory.removeFromThreads(key, this);
} catch (Throwable e) {
Log.log(e);
}
dispose();
}
}
use of org.python.pydev.ast.analysis.messages.IMessage in project Pydev by fabioz.
the class TabNanny method analyzeDoc.
/**
* Analyze the doc for mixed tabs and indents with the wrong number of chars.
* @param monitor
*
* @return a list with the error messages to be shown to the user.
*/
public static List<IMessage> analyzeDoc(IDocument doc, IAnalysisPreferences analysisPrefs, String moduleName, IIndentPrefs indentPrefs, IProgressMonitor monitor) {
ArrayList<IMessage> ret = new ArrayList<IMessage>();
// don't even try to gather indentation errors if they should be ignored.
if (analysisPrefs.getSeverityForType(IAnalysisPreferences.TYPE_INDENTATION_PROBLEM) < IMarker.SEVERITY_INFO) {
return ret;
}
List<IndentInfo> foundTabs = new ArrayList<IndentInfo>();
List<IndentInfo> foundSpaces = new ArrayList<IndentInfo>();
TabNannyDocIterator it;
try {
it = new TabNannyDocIterator(doc);
} catch (BadLocationException e) {
return ret;
}
while (it.hasNext()) {
IndentInfo indentation;
try {
indentation = it.next();
} catch (BadLocationException e) {
return ret;
}
// it can actually be in both (if we have spaces and tabs in the same indent line).
if (indentation.indent.indexOf('\t') != -1) {
foundTabs.add(indentation);
}
if (indentation.indent.indexOf(' ') != -1) {
foundSpaces.add(indentation);
}
if (monitor.isCanceled()) {
return ret;
}
}
int spacesFoundSize = foundSpaces.size();
int tabsFoundSize = foundTabs.size();
if (spacesFoundSize == 0 && tabsFoundSize == 0) {
// nothing to do here... (no indents available)
return ret;
}
// let's discover whether we should mark the tabs found as errors or the spaces found...
boolean markTabsAsError;
// if we found the same number of indents for tabs and spaces, let's use the user-prefs to decide what to do
if (spacesFoundSize == tabsFoundSize) {
// ok, we have both, spaces and tabs... let's see what the user actually wants
markTabsAsError = indentPrefs.getUseSpaces(false);
} else if (tabsFoundSize > spacesFoundSize) {
// let's see what appears more in the file (and mark the other as error).
markTabsAsError = false;
} else {
markTabsAsError = true;
}
List<IndentInfo> errorsAre;
List<IndentInfo> validsAre;
String errorMsg;
char errorChar;
if (markTabsAsError) {
validsAre = foundSpaces;
errorsAre = foundTabs;
errorMsg = "Mixed Indentation: Tab found";
errorChar = '\t';
createBadIndentForSpacesMessages(doc, analysisPrefs, indentPrefs, ret, validsAre, monitor);
} else {
validsAre = foundTabs;
errorsAre = foundSpaces;
errorMsg = "Mixed Indentation: Spaces found";
errorChar = ' ';
}
createMixedErrorMessages(doc, analysisPrefs, ret, errorsAre, errorMsg, errorChar, monitor);
return ret;
}
use of org.python.pydev.ast.analysis.messages.IMessage in project Pydev by fabioz.
the class TabNanny method createBadIndentForSpacesMessages.
/**
* Creates the errors that are related to a bad indentation (number of space chars is not ok).
* @param monitor
*/
private static void createBadIndentForSpacesMessages(IDocument doc, IAnalysisPreferences analysisPrefs, IIndentPrefs indentPrefs, ArrayList<IMessage> ret, List<IndentInfo> validsAre, IProgressMonitor monitor) {
int tabWidth = indentPrefs.getTabWidth();
// if we're analyzing the spaces, let's mark invalid indents (tabs are not searched for those because
// a tab always marks a full indent).
FastStringBuffer buffer = new FastStringBuffer();
for (IndentInfo indentation : validsAre) {
if (monitor.isCanceled()) {
return;
}
if (!indentation.hasNonIndentChars) {
// if it does not have more contents (its only whitespaces), let's keep on going!
continue;
}
String indentStr = indentation.indent;
if (indentStr.indexOf("\t") != -1) {
// the ones that appear in tabs and spaces should not be analyzed here (they'll have their own error messages).
continue;
}
int lenFound = indentStr.length();
int extraChars = lenFound % tabWidth;
if (extraChars != 0) {
Integer offset = indentation.startOffset;
int startLine = PySelection.getLineOfOffset(doc, offset) + 1;
int startCol = 1;
int endCol = startCol + lenFound;
buffer.clear();
ret.add(new Message(IAnalysisPreferences.TYPE_INDENTATION_PROBLEM, buffer.append("Bad Indentation (").append(lenFound).append(" spaces)").toString(), startLine, startLine, startCol, endCol, analysisPrefs));
}
}
}
use of org.python.pydev.ast.analysis.messages.IMessage in project Pydev by fabioz.
the class TabNanny method createMixedErrorMessages.
/**
* Creates the errors that are related to the mixed indentation.
* @param monitor
*/
private static void createMixedErrorMessages(IDocument doc, IAnalysisPreferences analysisPrefs, ArrayList<IMessage> ret, List<IndentInfo> errorsAre, String errorMsg, char errorChar, IProgressMonitor monitor) {
for (IndentInfo indentation : errorsAre) {
if (monitor.isCanceled()) {
return;
}
Integer offset = indentation.startOffset;
int startLine = PySelection.getLineOfOffset(doc, offset) + 1;
IRegion region;
try {
region = doc.getLineInformationOfOffset(offset);
int startCol = offset - region.getOffset() + 1;
String indentationString = indentation.indent;
int charIndex = indentationString.indexOf(errorChar);
startCol += charIndex;
// now, get the endCol
int endCol = startCol;
int indentationStringLen = indentationString.length();
// endCol starts at 1, but string access starts at 0 (so <= is needed)
while (endCol <= indentationStringLen) {
if (indentationString.charAt(endCol - 1) == errorChar) {
endCol++;
} else {
break;
}
}
ret.add(new Message(IAnalysisPreferences.TYPE_INDENTATION_PROBLEM, errorMsg, startLine, startLine, startCol, endCol, analysisPrefs));
} catch (BadLocationException e) {
Log.log(e);
}
}
}
use of org.python.pydev.ast.analysis.messages.IMessage in project Pydev by fabioz.
the class MessagesManager method getMessages.
/**
* @return the generated messages.
*/
public List<IMessage> getMessages() {
List<IMessage> result = new ArrayList<IMessage>();
// let's get the messages
for (List<IMessage> l : messages.values()) {
if (l.size() < 1) {
// we need at least one message
continue;
}
Map<Integer, List<IMessage>> messagesByType = getMessagesByType(l);
for (int type : messagesByType.keySet()) {
l = messagesByType.get(type);
// the values are guaranteed to have size at least equal to 1
IMessage message = l.get(0);
// messages are grouped by type, and the severity is set by type, so, this is ok...
if (message.getSeverity() < IMarker.SEVERITY_INFO) {
if (doIgnoreMessageIfJustInformational(message.getType())) {
// used anyways for other actions)
continue;
}
}
if (l.size() == 1) {
// don't add additional info: not being used
// addAdditionalInfoToUnusedWildImport(message);
addToResult(result, message);
} else {
// the generator token has many associated messages - the messages may have different types,
// so, we need to get them by types
IToken generator = message.getGenerator();
CompositeMessage compositeMessage;
if (generator != null) {
compositeMessage = new CompositeMessage(message.getType(), generator, prefs);
} else {
compositeMessage = new CompositeMessage(message.getType(), message.getStartLine(document), message.getEndLine(document), message.getStartCol(document), message.getEndCol(document), prefs);
}
for (IMessage m : l) {
compositeMessage.addMessage(m);
}
// don't add additional info: not being used
// addAdditionalInfoToUnusedWildImport(compositeMessage);
addToResult(result, compositeMessage);
}
}
}
for (IMessage message : independentMessages) {
if (message.getSeverity() < IMarker.SEVERITY_INFO) {
if (doIgnoreMessageIfJustInformational(message.getType())) {
// used anyways for other actions)
continue;
}
// otherwise keep on and add it (needed for some actions)
}
addToResult(result, message);
}
return result;
}
Aggregations