<commit_before>package com.intellij.codeInsight.completion;

import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateEditingAdapter;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.util.MemberChooser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorHighlighter;
import com.intellij.openapi.editor.ex.HighlighterIterator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.java.IJavaElementType;
import com.intellij.util.IncorrectOperationException;

import java.util.ArrayList;
import java.util.List;

public class DefaultInsertHandler implements InsertHandler,Cloneable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.DefaultInsertHandler");

  protected static final Object EXPANDED_TEMPLATE_ATTR = Key.create("EXPANDED_TEMPLATE_ATTR");

  protected CompletionContext myContext;
  private int myStartOffset;
  private LookupData myLookupData;
  private LookupItem myLookupItem;

  private Project myProject;
  private PsiFile myFile;
  private Editor myEditor;
  protected Document myDocument;
  private InsertHandlerState myState;

  public void handleInsert(final CompletionContext context,
                           int startOffset, LookupData data, LookupItem item,
                           final boolean signatureSelected, final char completionChar) {
    DefaultInsertHandler delegate = this;

    if (isTemplateToBeCompleted(item)) {
      try {
        delegate = (DefaultInsertHandler)clone();
        delegate.clear();
      }
      catch (CloneNotSupportedException e) {
        e.printStackTrace();
      }
    }

    boolean toClear = true;
    try{
      toClear = delegate.handleInsertInner(context, startOffset, data, item, signatureSelected, completionChar);
    }
    finally{
      if (toClear) {
        delegate.clear();
      }
    }
  }

  private void clear() {
    myEditor = null;
    myDocument = null;
    myProject = null;
    myFile = null;
    myState = null;
    myLookupData = null;
    myLookupItem = null;
    myContext = null;
  }

  public boolean handleInsertInner(CompletionContext context,
                           int startOffset, LookupData data, LookupItem item,
                           final boolean signatureSelected, final char completionChar) {

    LOG.assertTrue(CommandProcessor.getInstance().getCurrentCommand() != null);
    PsiDocumentManager.getInstance(context.project).commitDocument(context.editor.getDocument());
    myContext = context;
    myStartOffset = startOffset;
    myLookupData = data;
    myLookupItem = item;

    myProject = myContext.project;
    myFile = myContext.file;
    myEditor = myContext.editor;
    myDocument = myEditor.getDocument();

    if (isTemplateToBeCompleted(myLookupItem)){
        handleTemplate(context, signatureSelected, completionChar);
      // we could not clear in this case since handleTemplate has templateFinished lisntener that works
      // with e.g. myLookupItem
        return false;
    }

    int tailType = getTailType(completionChar);

    adjustContextAfterLookupStringInsertion();
    myState = new InsertHandlerState(myContext.selectionEndOffset, myContext.selectionEndOffset);

    final boolean overwrite = completionChar != 0
      ? completionChar == Lookup.REPLACE_SELECT_CHAR
      : myLookupItem.getAttribute(LookupItem.OVERWRITE_ON_AUTOCOMPLETE_ATTR) != null;


    final boolean needLeftParenth = isToInsertParenth(tailType);
    final boolean hasParams = needLeftParenth && hasParams(signatureSelected);
    tailType = modifyTailTypeBasedOnMethodReturnType(signatureSelected, needLeftParenth, hasParams, tailType);

    if (overwrite)
      removeEndOfIdentifier(needLeftParenth && hasParams);
    else if(myContext.identifierEndOffset != myContext.selectionEndOffset)
      context.resetParensInfo();

    handleParenses(hasParams, needLeftParenth, tailType);
    handleBrackets();

    RangeMarker saveMaker = null;
    final boolean generateAnonymousBody = myLookupItem.getAttribute(LookupItem.GENERATE_ANONYMOUS_BODY_ATTR) != null;
    if (generateAnonymousBody){
      saveMaker = myDocument.createRangeMarker(myState.caretOffset, myState.caretOffset);
      myDocument.insertString(myState.tailOffset, "{}");
      myState.caretOffset = myState.tailOffset + 1;
      myState.tailOffset += 2;
    }

    myState.caretOffset = processTail(tailType, myState.caretOffset, myState.tailOffset);

    myEditor.getCaretModel().moveToOffset(myState.caretOffset);
    myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
    myEditor.getSelectionModel().removeSelection();

    try{
      myStartOffset = addImportForItem(myFile, myStartOffset, myLookupItem);
    }
    catch(IncorrectOperationException e){
      LOG.error(e);
    }

    if (needLeftParenth && hasParams){
      // Invoke parameters popup
      final PsiMethod method = myLookupItem.getObject() instanceof PsiMethod ? (PsiMethod)myLookupItem.getObject() : null;
      AutoPopupController.getInstance(myProject).autoPopupParameterInfo(myEditor, signatureSelected ? method : null);
    }

    if (tailType == TailType.DOT){
      AutoPopupController.getInstance(myProject).autoPopupMemberLookup(myEditor);
    }

    if (generateAnonymousBody){
      generateAnonymousBody();
      if (hasParams){
        int offset = saveMaker.getStartOffset();
        myEditor.getCaretModel().moveToOffset(offset);
        myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
        myEditor.getSelectionModel().removeSelection();
      }
      return false;
    }

    if (insertingAnnotation()) {
      final Document document = context.editor.getDocument();
      PsiDocumentManager.getInstance(context.project).commitDocument(document);
      int expectedDogOffset = myStartOffset;

      PsiElement elementAt = myFile.findElementAt(expectedDogOffset - 1);
      final PsiJavaCodeReferenceElement javaCodeRef = PsiTreeUtil.getParentOfType(elementAt, PsiJavaCodeReferenceElement.class);

      if (javaCodeRef != null) {
        elementAt = myFile.findElementAt(
          (expectedDogOffset = javaCodeRef.getTextRange().getStartOffset()) - 1
        );
      }

      if(!"@".equals(elementAt.getText()) &&
         PsiTreeUtil.getParentOfType(elementAt,PsiImportStatement.class) == null
        ) {
        document.insertString(expectedDogOffset, "@");
      }
    }
    return true;
  }

  private static boolean isTemplateToBeCompleted(final LookupItem lookupItem) {
    return lookupItem.getObject() instanceof Template
           && lookupItem.getAttribute(EXPANDED_TEMPLATE_ATTR) == null;
  }

  private int modifyTailTypeBasedOnMethodReturnType(boolean signatureSelected, boolean needLeftParenth, boolean hasParams, int tailType) {
    Object completion = myLookupItem.getObject();
    if(completion instanceof PsiMethod){
      final PsiMethod method = ((PsiMethod)completion);
      if (signatureSelected) {
        if(PsiType.VOID.equals(method.getReturnType()) && !(myContext.file instanceof PsiCodeFragment)) {
          tailType = TailType.SEMICOLON;
        }
      }
      else {
        final boolean hasOverloads = hasOverloads();
        if (!hasOverloads) {
          if(PsiType.VOID.equals(method.getReturnType()) && !(myContext.file instanceof PsiCodeFragment)) {
            tailType = TailType.SEMICOLON;
          }
        }

        // [dsl]todo[dsl,ven,ik]: need to write something better here
      }
    }
    return tailType;
  }

  private void adjustContextAfterLookupStringInsertion(){
    // Handling lookup auto insert
    myContext.shiftOffsets(myLookupItem.getLookupString().length() - myContext.prefix.length() - (myContext.selectionEndOffset - myContext.startOffset));
  }

  private void handleBrackets(){
    // brackets
    final Integer bracketsAttr = (Integer)myLookupItem.getAttribute(LookupItem.BRACKETS_COUNT_ATTR);
    if (bracketsAttr != null){
      int count = bracketsAttr.intValue();
      if(count > 0)
        myState.caretOffset = myState.tailOffset + 1;
      for(int i = 0; i < count; i++){
        myDocument.insertString(myState.tailOffset, "[]");
        myState.tailOffset += 2;
      }
    }
  }

  private void handleParenses(final boolean hasParams, final boolean needParenth, int tailType){
    final CodeInsightSettings settings = CodeInsightSettings.getInstance();
    final boolean myGenerateAnonymousBody = myLookupItem.getAttribute(LookupItem.GENERATE_ANONYMOUS_BODY_ATTR) != null;
    boolean insertRightParenth = !settings.INSERT_SINGLE_PARENTH
                                 || (settings.INSERT_DOUBLE_PARENTH_WHEN_NO_ARGS && !hasParams)
                                 || myGenerateAnonymousBody
                                 || (tailType != TailType.NONE && tailType != TailType.LPARENTH);

//    if(tailType == TailType.LPARENTH) tailType = TailType.NONE; //???
    if (needParenth){
      if (myContext.lparenthOffset >= 0){
        myState.tailOffset = myContext.argListEndOffset;
        if (myContext.rparenthOffset < 0 && insertRightParenth){
          myDocument.insertString(myState.tailOffset, ")");
          myState.tailOffset += 1;
          myContext.argListEndOffset = myState.tailOffset;
        }
        if (hasParams){
          myState.caretOffset = myContext.lparenthOffset + 1;
        }
        else{
          myState.caretOffset = myContext.argListEndOffset;
        }
      }
      else{
        final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myProject);
        myState.tailOffset = myContext.selectionEndOffset;
        myState.caretOffset = myContext.selectionEndOffset;

        if(styleSettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES){
          myDocument.insertString(myState.tailOffset++, " ");
          myState.caretOffset ++;
        }
        if (insertRightParenth &&
            (tailType != TailType.CALL_RPARENTH || myGenerateAnonymousBody)
           ){
          myDocument.insertString(myState.tailOffset, "()");
          myState.tailOffset += 2;
          if (hasParams){
            myState.caretOffset++;
          }
          else{
            myState.caretOffset += 2;
          }
        }
        else{
          myDocument.insertString(myState.tailOffset++, "(");
          myState.caretOffset ++;
        }

        if(hasParams && styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES){
          myDocument.insertString(myState.caretOffset++, " ");
          myState.tailOffset++;
        }
      }
    }
  }

  private boolean isToInsertParenth(int tailType){
    boolean needParens = false;
    if (tailType == TailType.LPARENTH){
      needParens = true;
    }
    else if (myLookupItem.getObject() instanceof PsiMethod){
      PsiElement place = myFile.findElementAt(myStartOffset);
      if (myLookupItem.getObject() instanceof PsiAnnotationMethod) {
        if (place instanceof PsiIdentifier && (place.getParent() instanceof PsiNameValuePair
                                            || place.getParent().getParent() instanceof PsiNameValuePair)) return false;
      }
      needParens = place == null || !(place.getParent() instanceof PsiImportStaticReferenceElement);
    }
    else if (myLookupItem.getAttribute(LookupItem.NEW_OBJECT_ATTR) != null){
      PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
      needParens = true;
      final PsiClass aClass = (PsiClass)myLookupItem.getObject();

      PsiElement place = myFile.findElementAt(myStartOffset);

      if(myLookupItem.getAttribute(LookupItem.DONT_CHECK_FOR_INNERS) == null){
        PsiClass[] classes = aClass.getInnerClasses();
        for (PsiClass inner : classes) {
          if (!inner.hasModifierProperty(PsiModifier.STATIC)) continue;
          if (!inner.getManager().getResolveHelper().isAccessible(inner, place, null)) continue;
          needParens = false;
          break;
        }
      }
    } else if (insertingAnnotationWithParameters()) {
      needParens = true;
    }
    return needParens;
  }

  private boolean hasParams(boolean signatureSelected){
    boolean hasParms = false;
    if (myLookupItem.getObject() instanceof PsiMethod){
      final PsiMethod method = (PsiMethod)myLookupItem.getObject();
      hasParms = method.getParameterList().getParameters().length > 0;
      if (!signatureSelected){
        hasParms = hasParms || hasOverloads();
      }
    }
    else if (myLookupItem.getAttribute(LookupItem.NEW_OBJECT_ATTR) != null){
      PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
      final PsiClass aClass = (PsiClass)myLookupItem.getObject();

      final PsiElement place = myFile.findElementAt(myStartOffset);

      final PsiMethod[] constructors = aClass.getConstructors();
      for (PsiMethod constructor : constructors) {
        if (!aClass.getManager().getResolveHelper().isAccessible(constructor, place, null)) continue;
        if (constructor.getParameterList().getParameters().length > 0) {
          hasParms = true;
          break;
        }
      }
    }
    else if(PsiKeyword.SYNCHRONIZED.equals(myLookupItem.getLookupString())
             || PsiKeyword.CATCH.equals(myLookupItem.getLookupString())
             || PsiKeyword.SWITCH.equals(myLookupItem.getLookupString()))
      hasParms = true;<commit_msg>synchronized keyword completion fix<commit_after>package com.intellij.codeInsight.completion;

import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateEditingAdapter;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.util.MemberChooser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorHighlighter;
import com.intellij.openapi.editor.ex.HighlighterIterator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.java.IJavaElementType;
import com.intellij.util.IncorrectOperationException;

import java.util.ArrayList;
import java.util.List;

public class DefaultInsertHandler implements InsertHandler,Cloneable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.DefaultInsertHandler");

  protected static final Object EXPANDED_TEMPLATE_ATTR = Key.create("EXPANDED_TEMPLATE_ATTR");

  protected CompletionContext myContext;
  private int myStartOffset;
  private LookupData myLookupData;
  private LookupItem myLookupItem;

  private Project myProject;
  private PsiFile myFile;
  private Editor myEditor;
  protected Document myDocument;
  private InsertHandlerState myState;

  public void handleInsert(final CompletionContext context,
                           int startOffset, LookupData data, LookupItem item,
                           final boolean signatureSelected, final char completionChar) {
    DefaultInsertHandler delegate = this;

    if (isTemplateToBeCompleted(item)) {
      try {
        delegate = (DefaultInsertHandler)clone();
        delegate.clear();
      }
      catch (CloneNotSupportedException e) {
        e.printStackTrace();
      }
    }

    boolean toClear = true;
    try{
      toClear = delegate.handleInsertInner(context, startOffset, data, item, signatureSelected, completionChar);
    }
    finally{
      if (toClear) {
        delegate.clear();
      }
    }
  }

  private void clear() {
    myEditor = null;
    myDocument = null;
    myProject = null;
    myFile = null;
    myState = null;
    myLookupData = null;
    myLookupItem = null;
    myContext = null;
  }

  public boolean handleInsertInner(CompletionContext context,
                           int startOffset, LookupData data, LookupItem item,
                           final boolean signatureSelected, final char completionChar) {

    LOG.assertTrue(CommandProcessor.getInstance().getCurrentCommand() != null);
    PsiDocumentManager.getInstance(context.project).commitDocument(context.editor.getDocument());
    myContext = context;
    myStartOffset = startOffset;
    myLookupData = data;
    myLookupItem = item;

    myProject = myContext.project;
    myFile = myContext.file;
    myEditor = myContext.editor;
    myDocument = myEditor.getDocument();

    if (isTemplateToBeCompleted(myLookupItem)){
        handleTemplate(context, signatureSelected, completionChar);
      // we could not clear in this case since handleTemplate has templateFinished lisntener that works
      // with e.g. myLookupItem
        return false;
    }

    int tailType = getTailType(completionChar);

    adjustContextAfterLookupStringInsertion();
    myState = new InsertHandlerState(myContext.selectionEndOffset, myContext.selectionEndOffset);

    final boolean overwrite = completionChar != 0
      ? completionChar == Lookup.REPLACE_SELECT_CHAR
      : myLookupItem.getAttribute(LookupItem.OVERWRITE_ON_AUTOCOMPLETE_ATTR) != null;


    final boolean needLeftParenth = isToInsertParenth(tailType);
    final boolean hasParams = needLeftParenth && hasParams(signatureSelected);
    tailType = modifyTailTypeBasedOnMethodReturnType(signatureSelected, needLeftParenth, hasParams, tailType);

    if (overwrite)
      removeEndOfIdentifier(needLeftParenth && hasParams);
    else if(myContext.identifierEndOffset != myContext.selectionEndOffset)
      context.resetParensInfo();

    handleParenses(hasParams, needLeftParenth, tailType);
    handleBrackets();

    RangeMarker saveMaker = null;
    final boolean generateAnonymousBody = myLookupItem.getAttribute(LookupItem.GENERATE_ANONYMOUS_BODY_ATTR) != null;
    if (generateAnonymousBody){
      saveMaker = myDocument.createRangeMarker(myState.caretOffset, myState.caretOffset);
      myDocument.insertString(myState.tailOffset, "{}");
      myState.caretOffset = myState.tailOffset + 1;
      myState.tailOffset += 2;
    }

    myState.caretOffset = processTail(tailType, myState.caretOffset, myState.tailOffset);

    myEditor.getCaretModel().moveToOffset(myState.caretOffset);
    myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
    myEditor.getSelectionModel().removeSelection();

    try{
      myStartOffset = addImportForItem(myFile, myStartOffset, myLookupItem);
    }
    catch(IncorrectOperationException e){
      LOG.error(e);
    }

    if (needLeftParenth && hasParams){
      // Invoke parameters popup
      final PsiMethod method = myLookupItem.getObject() instanceof PsiMethod ? (PsiMethod)myLookupItem.getObject() : null;
      AutoPopupController.getInstance(myProject).autoPopupParameterInfo(myEditor, signatureSelected ? method : null);
    }

    if (tailType == TailType.DOT){
      AutoPopupController.getInstance(myProject).autoPopupMemberLookup(myEditor);
    }

    if (generateAnonymousBody){
      generateAnonymousBody();
      if (hasParams){
        int offset = saveMaker.getStartOffset();
        myEditor.getCaretModel().moveToOffset(offset);
        myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
        myEditor.getSelectionModel().removeSelection();
      }
      return false;
    }

    if (insertingAnnotation()) {
      final Document document = context.editor.getDocument();
      PsiDocumentManager.getInstance(context.project).commitDocument(document);
      int expectedDogOffset = myStartOffset;

      PsiElement elementAt = myFile.findElementAt(expectedDogOffset - 1);
      final PsiJavaCodeReferenceElement javaCodeRef = PsiTreeUtil.getParentOfType(elementAt, PsiJavaCodeReferenceElement.class);

      if (javaCodeRef != null) {
        elementAt = myFile.findElementAt(
          (expectedDogOffset = javaCodeRef.getTextRange().getStartOffset()) - 1
        );
      }

      if(!"@".equals(elementAt.getText()) &&
         PsiTreeUtil.getParentOfType(elementAt,PsiImportStatement.class) == null
        ) {
        document.insertString(expectedDogOffset, "@");
      }
    }
    return true;
  }

  private static boolean isTemplateToBeCompleted(final LookupItem lookupItem) {
    return lookupItem.getObject() instanceof Template
           && lookupItem.getAttribute(EXPANDED_TEMPLATE_ATTR) == null;
  }

  private int modifyTailTypeBasedOnMethodReturnType(boolean signatureSelected, boolean needLeftParenth, boolean hasParams, int tailType) {
    Object completion = myLookupItem.getObject();
    if(completion instanceof PsiMethod){
      final PsiMethod method = ((PsiMethod)completion);
      if (signatureSelected) {
        if(PsiType.VOID.equals(method.getReturnType()) && !(myContext.file instanceof PsiCodeFragment)) {
          tailType = TailType.SEMICOLON;
        }
      }
      else {
        final boolean hasOverloads = hasOverloads();
        if (!hasOverloads) {
          if(PsiType.VOID.equals(method.getReturnType()) && !(myContext.file instanceof PsiCodeFragment)) {
            tailType = TailType.SEMICOLON;
          }
        }

        // [dsl]todo[dsl,ven,ik]: need to write something better here
      }
    }
    return tailType;
  }

  private void adjustContextAfterLookupStringInsertion(){
    // Handling lookup auto insert
    myContext.shiftOffsets(myLookupItem.getLookupString().length() - myContext.prefix.length() - (myContext.selectionEndOffset - myContext.startOffset));
  }

  private void handleBrackets(){
    // brackets
    final Integer bracketsAttr = (Integer)myLookupItem.getAttribute(LookupItem.BRACKETS_COUNT_ATTR);
    if (bracketsAttr != null){
      int count = bracketsAttr.intValue();
      if(count > 0)
        myState.caretOffset = myState.tailOffset + 1;
      for(int i = 0; i < count; i++){
        myDocument.insertString(myState.tailOffset, "[]");
        myState.tailOffset += 2;
      }
    }
  }

  private void handleParenses(final boolean hasParams, final boolean needParenth, int tailType){
    final CodeInsightSettings settings = CodeInsightSettings.getInstance();
    final boolean myGenerateAnonymousBody = myLookupItem.getAttribute(LookupItem.GENERATE_ANONYMOUS_BODY_ATTR) != null;
    boolean insertRightParenth = !settings.INSERT_SINGLE_PARENTH
                                 || (settings.INSERT_DOUBLE_PARENTH_WHEN_NO_ARGS && !hasParams)
                                 || myGenerateAnonymousBody
                                 || (tailType != TailType.NONE && tailType != TailType.LPARENTH);

//    if(tailType == TailType.LPARENTH) tailType = TailType.NONE; //???
    if (needParenth){
      if (myContext.lparenthOffset >= 0){
        myState.tailOffset = myContext.argListEndOffset;
        if (myContext.rparenthOffset < 0 && insertRightParenth){
          myDocument.insertString(myState.tailOffset, ")");
          myState.tailOffset += 1;
          myContext.argListEndOffset = myState.tailOffset;
        }
        if (hasParams){
          myState.caretOffset = myContext.lparenthOffset + 1;
        }
        else{
          myState.caretOffset = myContext.argListEndOffset;
        }
      }
      else{
        final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myProject);
        myState.tailOffset = myContext.selectionEndOffset;
        myState.caretOffset = myContext.selectionEndOffset;

        if(styleSettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES){
          myDocument.insertString(myState.tailOffset++, " ");
          myState.caretOffset ++;
        }
        if (insertRightParenth &&
            (tailType != TailType.CALL_RPARENTH || myGenerateAnonymousBody)
           ){
          myDocument.insertString(myState.tailOffset, "()");
          myState.tailOffset += 2;
          if (hasParams){
            myState.caretOffset++;
          }
          else{
            myState.caretOffset += 2;
          }
        }
        else{
          myDocument.insertString(myState.tailOffset++, "(");
          myState.caretOffset ++;
        }

        if(hasParams && styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES){
          myDocument.insertString(myState.caretOffset++, " ");
          myState.tailOffset++;
        }
      }
    }
  }

  private boolean isToInsertParenth(int tailType){
    boolean needParens = false;
    if (tailType == TailType.LPARENTH){
      needParens = true;
    }
    else if (myLookupItem.getObject() instanceof PsiMethod){
      PsiElement place = myFile.findElementAt(myStartOffset);
      if (myLookupItem.getObject() instanceof PsiAnnotationMethod) {
        if (place instanceof PsiIdentifier && (place.getParent() instanceof PsiNameValuePair
                                            || place.getParent().getParent() instanceof PsiNameValuePair)) return false;
      }
      needParens = place == null || !(place.getParent() instanceof PsiImportStaticReferenceElement);
    }
    else if (myLookupItem.getAttribute(LookupItem.NEW_OBJECT_ATTR) != null){
      PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
      needParens = true;
      final PsiClass aClass = (PsiClass)myLookupItem.getObject();

      PsiElement place = myFile.findElementAt(myStartOffset);

      if(myLookupItem.getAttribute(LookupItem.DONT_CHECK_FOR_INNERS) == null){
        PsiClass[] classes = aClass.getInnerClasses();
        for (PsiClass inner : classes) {
          if (!inner.hasModifierProperty(PsiModifier.STATIC)) continue;
          if (!inner.getManager().getResolveHelper().isAccessible(inner, place, null)) continue;
          needParens = false;
          break;
        }
      }
    } else if (insertingAnnotationWithParameters()) {
      needParens = true;
    }
    return needParens;
  }

  private boolean hasParams(boolean signatureSelected){
    boolean hasParms = false;
    if (myLookupItem.getObject() instanceof PsiMethod){
      final PsiMethod method = (PsiMethod)myLookupItem.getObject();
      hasParms = method.getParameterList().getParameters().length > 0;
      if (!signatureSelected){
        hasParms = hasParms || hasOverloads();
      }
    }
    else if (myLookupItem.getAttribute(LookupItem.NEW_OBJECT_ATTR) != null){
      PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
      final PsiClass aClass = (PsiClass)myLookupItem.getObject();

      final PsiElement place = myFile.findElementAt(myStartOffset);

      final PsiMethod[] constructors = aClass.getConstructors();
      for (PsiMethod constructor : constructors) {
        if (!aClass.getManager().getResolveHelper().isAccessible(constructor, place, null)) continue;
        if (constructor.getParameterList().getParameters().length > 0) {
          hasParms = true;
          break;
        }
      }
    }
    else if (PsiKeyword.SYNCHRONIZED.equals(myLookupItem.getLookupString())) {
      final PsiElement place = myFile.findElementAt(myStartOffset);
      hasParms = PsiTreeUtil.getParentOfType(place, PsiMember.class, PsiCodeBlock.class) instanceof PsiCodeBlock;
    }
    else if(PsiKeyword.CATCH.equals(myLookupItem.getLookupString())
             || PsiKeyword.SWITCH.equals(myLookupItem.getLookupString()))
      hasParms = true;
{'fraction_non_alphanumeric': 0.09646324078473967, 'fraction_numerical': 0.0011540289186070193, 'mean_word_length': 3.4722222222222223, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4233105', 'n_tokens_mistral': 8497, 'n_tokens_neox': 8345, 'n_words': 1464}