CompileContext#addMessage doesn't honor line and column

Answered

Hello,

I am writing a CompileTask plugin.  I have performed all the analysis that I desired and now want to output information to the Build view.  I have found that I can use CompileTask#addMessage.  However, when the message is shown in the Build view, the line information is not presented (it always shows 1) and the URL link does not jump to the error location in the file.

How do I create a message in the Build view that has the proper line and column information as well as the correct URL?

Thanks

p.s. When I use virtualFile.getPresentableUrl(), there is no URL in the Build view associated with the error.

------------------------

This is what I am doing to generate the information for the addMessage function:

// Note:  When I use virtualFile.getPresentableUrl(), 
// there is no URL in the Build view associated with the error.
final String url = virtualFile.getUrl();
final Set<MessageInfo> messageInfoSet = new TreeSet<>();
for (final HighlightInfo highlightInfo : fileWithErrors.getHighlightInfoSet())
{
String message = "One or more inspections has resulted in an error";
int line = -1;
int column = -1;

final RangeHighlighterEx highlighter = highlightInfo.getHighlighter();
if (null != highlighter && highlighter.isValid())
{
message = highlightInfo.getDescription();

final int startOffset = highlighter.getStartOffset();
final LineColumn lineColumn =
StringUtil.offsetToLineColumn(psiFile.getText(), startOffset);
line = lineColumn.line;
column = lineColumn.column;
}
compileContext.addMessage(
CompilerMessageCategory.ERROR,message, url, line, column, psiFile))
// NOTE: psiFile was determined in another method and is associated with the
// virtualFile
}
5 comments
Comment actions Permalink

This is how I retrieved the psiFile:

 

final Set<Pair<VirtualFile, PsiFile>> filesSet =
virtualFiles.parallelStream()
.filter(virtualFile -> !virtualFile.isDirectory())
.map(virtualFile ->
{
final Object item = findFileSystemItem(project, virtualFile);
if (item instanceof PsiFile)
{
return new Pair<>(virtualFile, (PsiFile)item);
}
return null;
}
).collect(Collectors.toSet());
0
Comment actions Permalink

Hi Todd,

Please try to (EDIT: try one of the following):

  • not pass psiFile as a Navigatable argument
  • pass the Navigatable element that points to an actual error element and -1 as line and column

In case you pass Navigatable, which is PsiFile in your case, line and column are ignored, and position of the passed Navigatable is used (in the case of PsiFile, it is always 1).

0
Comment actions Permalink

Thanks, Karol Lewandowski.  This is a long post as I want to show you the code I am using. 

Could you give me another hint?  Any help is appreciated.

I wrote a method to check for types that are Navigatable in method return types and field types in the classes I have found accessible to me.  Unfortunately, the only results out of 1020 classes were PsiDirectory, PsiFileSystemItem, PsiFile, and, of course, Navigatable; nothing related to errors

I examined the following classes as those were the classes I have accessible to me:

  • com.intellij.codeInsight.daemon.impl.HighlightInfo
  • com.intellij.codeInspection.CommonProblemDescriptor
  • com.intellij.codeInspection.ex.InspectionToolWrapper
  • com.intellij.codeInspection.GlobalInspectionContext
  • com.intellij.codeInspection.InspectionEngine
  • com.intellij.codeInspection.InspectionManager
  • com.intellij.codeInspection.InspectionProfile
  • com.intellij.codeInspection.ProblemDescriptor
  • com.intellij.lang.annotation.HighlightSeverity
  • com.intellij.openapi.compiler.CompileContext
  • com.intellij.openapi.compiler.CompilerMessageCategory
  • com.intellij.openapi.compiler.CompileScope
  • com.intellij.openapi.compiler.CompileTask
  • com.intellij.openapi.editor.Document
  • com.intellij.openapi.editor.ex.RangeHighlighterEx
  • com.intellij.openapi.editor.impl.DocumentMarkupModel
  • com.intellij.openapi.editor.markup.MarkupModel
  • com.intellij.openapi.editor.markup.RangeHighlighter
  • com.intellij.openapi.project.Project
  • com.intellij.openapi.roots.ProjectFileIndex
  • com.intellij.openapi.util.Pair
  • com.intellij.openapi.vfs.VirtualFile
  • com.intellij.pom.Navigatable
  • com.intellij.profile.codeInspection.ProjectInspectionProfileManager
  • com.intellij.psi.PsiDocumentManager
  • com.intellij.psi.PsiFile

I performed the search using the following code:


private static final Set<Class<?>> tried = new HashSet<>();
private static final Set<Class<?>> navigatable = new HashSet<>();

public static void findNavigatables(final Class<?> clazz)
{
if (tried.contains(clazz))
{
return;
}

tried.add(clazz);
if (Navigatable.class.isAssignableFrom(clazz)
&& clazz != Object.class)
{
navigatable.add(clazz);
}

final Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods)
{
final Class<?> returnType = method.getReturnType();
if (tried.contains(returnType))
{
continue;
}

if (Navigatable.class.isAssignableFrom(returnType)
&& returnType != Object.class)
{
navigatable.add(returnType);
}
findNavigatables(returnType);
}

final Field[] fields = clazz.getDeclaredFields();
for (final Field field : fields)
{
final Class<?> fieldType = field.getType();
if (tried.contains(fieldType))
{
continue;
}

if (Navigatable.class.isAssignableFrom(fieldType)
&& fieldType != Object.class)
{
navigatable.add(fieldType);
}
findNavigatables(fieldType);
}
}

 

This is how I find the HighlightInfo (psiFile and project are known):


final Document document =
PsiDocumentManager.getInstance(project).getDocument(psiFile);
if (null == document)
{
continue;
}

final MarkupModel markup = DocumentMarkupModel.forDocument(document, project, true);

final Set<HighlightInfo> highlightInfoSet =
new TreeSet<>(new HighlightInfoComparator());

final RangeHighlighter[] allHighlighters = markup.getAllHighlighters();
for (final RangeHighlighter highlighter : allHighlighters)
{
if (!highlighter.isValid())
{
continue;
}

final Object tooltip = highlighter.getErrorStripeTooltip();

if (tooltip instanceof HighlightInfo)
{
// Contains level of the highlighting (HighlightInfoType), ranges, fixes, etc.
final HighlightInfo info = (HighlightInfo)tooltip;

// Only concerned about inspections
if (null != info.getInspectionToolId())
{
final HighlightSeverity severity = info.getSeverity();
if (0 == HighlightSeverity.ERROR.compareTo(severity))
{
highlightInfoSet.add(info);
}
}
}
}

// Store what was found
if (!highlightInfoSet.isEmpty())
{
filesWithErrors.add(
new FileWithErrors(files.getFirst(), psiFile, highlightInfoSet));
}

 FileWithErrors is my own POJO DAO.

I am at a loss as to how to find the proper information to make a useful CompileContext message.

 

0
Comment actions Permalink

Hi Todd,

It is unclear to me if you tried solutions from my answer. If yes, what is the result?

For me, it seems that the problem is in adding the message:

compileContext.addMessage(CompilerMessageCategory.ERROR, message, url, line, column, psiFile)

In this case, line and column are ignored, and the psiFile element offset is applied, which for files is naturally 1.

If you have the correct line and column, just try:

compileContext.addMessage(CompilerMessageCategory.ERROR, message, url, line, column)

so skip the psiFile.

0
Comment actions Permalink

Hi Karol Lewandowski,

Thank you for clearing that up.  I misinterpreted your first post to mean that I should not pass the psiFile as the Navigatable and that I had to find a Navigatable associated with the error to use in it's place.  That was why I started searching for other Navigatables.

Leaving off the Navigatable all together worked as you expected it would.

Thank you again for all of your help!

0

Please sign in to leave a comment.