/*
 * Copyright 2000-2016 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.util;

import com.intellij.codeInsight.highlighting.HighlightErrorFilter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SyntaxTraverser;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import org.jetbrains.annotations.NotNull;

public class PsiErrorElementUtil {

  private static final Key<CachedValue<Boolean>> CONTAINS_ERROR_ELEMENT = Key.create("CONTAINS_ERROR_ELEMENT");

  private PsiErrorElementUtil() {}

  public static boolean hasErrors(@NotNull final Project project, @NotNull final VirtualFile virtualFile) {
    return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> {
      if (project.isDisposed() || !virtualFile.isValid()) return false;

      PsiManagerEx psiManager = PsiManagerEx.getInstanceEx(project);
      PsiFile psiFile = psiManager.getFileManager().findFile(virtualFile);
      return psiFile != null && hasErrors(psiFile);
    });
  }

  private static boolean hasErrors(@NotNull final PsiFile psiFile) {
    CachedValuesManager cachedValuesManager = CachedValuesManager.getManager(psiFile.getProject());
    return cachedValuesManager.getCachedValue(
      psiFile, CONTAINS_ERROR_ELEMENT,
      () -> CachedValueProvider.Result.create(hasErrorElements(psiFile), psiFile),
      false
    );
  }

  private static boolean hasErrorElements(@NotNull PsiElement element) {
    HighlightErrorFilter[] filters = Extensions.getExtensions(HighlightErrorFilter.EP_NAME, element.getProject());
    for (PsiErrorElement error : SyntaxTraverser.psiTraverser(element).traverse().filter(PsiErrorElement.class)) {
      for (HighlightErrorFilter filter : filters) {
        if (!filter.shouldHighlightErrorElement(error)) {
          return false;
        }
      }
    }
    return true;
  }
}

@@ -753,59 +753,8 @@
 er;%0A
-import com.intellij.openapi.extensions.Extensions;%0A
 impo
@@ -794,16 +794,16 @@
 roject;%0A
+
 import c
@@ -1529,22 +1529,16 @@
 NotNull 
-final 
 Project 
@@ -1555,22 +1555,16 @@
 NotNull 
-final 
 VirtualF
@@ -1998,22 +1998,16 @@
 NotNull 
-final 
 PsiFile 
@@ -2424,33 +2424,183 @@
 s = 
-Extensions.getExtensions(
+null;%0A    for (PsiErrorElement errorElement : SyntaxTraverser.psiTraverser(element).traverse().filter(PsiErrorElement.class)) %7B%0A      if (filters == null) %7B%0A        filters = 
 High
@@ -2623,18 +2623,31 @@
 .EP_NAME
-, 
+.getExtensions(
 element.
@@ -2661,32 +2661,53 @@
 ect());%0A    
-for (Psi
+  %7D%0A      if (shouldHighlight
 ErrorElement
@@ -2710,101 +2710,221 @@
 ment
- 
+(
 error
- : SyntaxTraverser.psiTraverser(element).traverse().filter(PsiErrorElement.class)
+Element, filters)) %7B%0A        return true;%0A      %7D%0A    %7D%0A    return false;%0A  %7D%0A%0A  private static boolean shouldHighlightErrorElement(@NotNull PsiErrorElement error, @NotNull HighlightErrorFilter%5B%5D filters
 ) %7B%0A
-  
     
@@ -2971,26 +2971,24 @@
 rs) %7B%0A      
- 
- 
 if (!filter.
@@ -3029,26 +3029,24 @@
 ) %7B%0A        
-  
 return false
@@ -3051,18 +3051,8 @@
 se;%0A
-        %7D%0A
     

fix PsiErrorElementUtil.hasErrors (a file without error elements was considered as one with errors) (WEB-24482)