public MultiNodeEditorData GetMultiNodeEditorData(ActionExecutionContext executionContext)
        {
            var multiNodeData = new MultiNodeEditorData {
                SynchronizedSegments = new SourcePosition[0]
            };
            var terminal = executionContext.DocumentRepository.Statements.GetTerminalAtPosition(executionContext.CaretOffset, n => !String.Equals(n.Id, Terminals.Comma) && !String.Equals(n.Id, Terminals.Dot) && !String.Equals(n.Id, Terminals.RightParenthesis));

            if (executionContext.SelectionLength > 0 || terminal?.Id.IsIdentifierOrAlias() != true)
            {
                return(multiNodeData);
            }

            multiNodeData.CurrentNode = terminal;

            var semanticModel = (OracleStatementSemanticModel)executionContext.DocumentRepository.ValidationModels[terminal.Statement].SemanticModel;

            OracleColumnReference columnReference;
            OracleQueryBlock      cteQueryBlock;

            switch (terminal.Id)
            {
            case Terminals.ObjectAlias:
                var objectReference = semanticModel.AllReferenceContainers
                                      .SelectMany(c => c.ObjectReferences)
                                      .SingleOrDefault(o => o.AliasNode == terminal);

                var synchronizedSegments = new List <SourcePosition>();
                cteQueryBlock = semanticModel.QueryBlocks.SingleOrDefault(qb => qb.AliasNode == terminal);
                if (objectReference == null && cteQueryBlock != null)
                {
                    synchronizedSegments.AddRange(GetDataObjectReferences(cteQueryBlock).Select(o => o.ObjectNode.SourcePosition));
                }

                var objectQualifiedColumnSynchronizedSegments = semanticModel.AllReferenceContainers
                                                                .SelectMany(c => c.ColumnReferences)
                                                                .Where(c => c.ObjectNode != null && c.ValidObjectReference != null && (c.ValidObjectReference == objectReference || IsCommonTableExpressionColumnReference(cteQueryBlock, c)))
                                                                .Concat(GetCommonTableExpressionObjectPrefixedColumnReferences(cteQueryBlock))
                                                                .Select(c => c.ObjectNode.SourcePosition);

                synchronizedSegments.AddRange(objectQualifiedColumnSynchronizedSegments);
                multiNodeData.SynchronizedSegments = synchronizedSegments.AsReadOnly();

                break;

            case Terminals.ObjectIdentifier:
                var editNodes = new List <SourcePosition>();

                columnReference = semanticModel.GetReference <OracleColumnReference>(terminal);

                var objectReferences             = new HashSet <OracleDataObjectReference>();
                var dataObjectReferenceCandidate = columnReference?.ValidObjectReference as OracleDataObjectReference;
                if (dataObjectReferenceCandidate != null)
                {
                    objectReferences.Add(dataObjectReferenceCandidate);
                }
                else
                {
                    dataObjectReferenceCandidate = semanticModel.GetReference <OracleDataObjectReference>(terminal);
                }

                if (dataObjectReferenceCandidate?.Type == ReferenceType.CommonTableExpression)
                {
                    objectReferences.Add(dataObjectReferenceCandidate);

                    if (dataObjectReferenceCandidate.QueryBlocks.Count == 1)
                    {
                        cteQueryBlock = dataObjectReferenceCandidate.QueryBlocks.First();
                        var cteColumnReferences = GetCommonTableExpressionObjectPrefixedColumnReferences(cteQueryBlock);
                        editNodes.AddRange(cteColumnReferences.Select(c => c.ObjectNode.SourcePosition));
                        editNodes.AddRange(GetDataObjectReferences(cteQueryBlock).Where(o => o != dataObjectReferenceCandidate).Select(o => o.ObjectNode.SourcePosition));

                        StatementGrammarNode cteAliasNode;
                        if (cteQueryBlock.AliasNode == null)
                        {
                            cteQueryBlock = cteQueryBlock.AllPrecedingConcatenatedQueryBlocks.Last();
                            cteAliasNode  = cteQueryBlock.AliasNode;
                            var referencesToCte = semanticModel.AllReferenceContainers.SelectMany(c => c.ObjectReferences).Where(o => o.QueryBlocks.Count == 1 && o.QueryBlocks.First() == cteQueryBlock);
                            objectReferences.UnionWith(referencesToCte);
                        }
                        else
                        {
                            cteAliasNode = cteQueryBlock.AliasNode;
                        }

                        editNodes.Add(cteAliasNode.SourcePosition);
                    }
                }

                foreach (var dataObjectReference in objectReferences)
                {
                    if (dataObjectReference.AliasNode != null && columnReference != null)
                    {
                        editNodes.Add(dataObjectReference.AliasNode.SourcePosition);
                    }
                    else if (dataObjectReference.Type == ReferenceType.CommonTableExpression && dataObjectReference.ObjectNode != terminal)
                    {
                        editNodes.Add(dataObjectReference.ObjectNode.SourcePosition);
                    }

                    if (dataObjectReference.AliasNode == null || columnReference != null)
                    {
                        var editNodesSource = semanticModel.AllReferenceContainers
                                              .SelectMany(c => c.ColumnReferences)
                                              .Where(r => r.ObjectNode != null && r != columnReference && r.ValidObjectReference == dataObjectReference)
                                              .Select(r => r.ObjectNode.SourcePosition);

                        editNodes.AddRange(editNodesSource);
                    }
                }

                multiNodeData.SynchronizedSegments = editNodes.AsReadOnly();
                break;

            case Terminals.BindVariableIdentifier:
                var bindVariable = FindUsagesCommand.GetBindVariable(semanticModel, terminal.Token.Value);
                multiNodeData.SynchronizedSegments = bindVariable.Nodes.Where(n => n != terminal).Select(t => t.SourcePosition).ToArray();
                break;

            case Terminals.ColumnAlias:
                var selectListColumn = semanticModel.AllReferenceContainers
                                       .OfType <OracleSelectListColumn>()
                                       .SingleOrDefault(c => c.AliasNode == terminal);

                if (selectListColumn != null)
                {
                    multiNodeData.SynchronizedSegments = FindUsagesCommand.GetParentQueryBlockColumnUsages(selectListColumn)
                                                         .TakeWhile(t => String.Equals(t.Token.Value.ToQuotedIdentifier(), selectListColumn.NormalizedName))
                                                         .Select(t => t.SourcePosition)
                                                         .ToArray();
                }
                else
                {
                    goto case Terminals.Identifier;
                }

                break;

            case Terminals.Identifier:
                multiNodeData.SynchronizedSegments = FindUsagesCommand.GetColumnUsages(semanticModel, terminal, true)
                                                     .Where(t => t != terminal)
                                                     .Select(t => t.SourcePosition)
                                                     .ToArray();
                break;
            }

            return(multiNodeData);
        }
Ejemplo n.º 2
0
		public MultiNodeEditorData GetMultiNodeEditorData(ActionExecutionContext executionContext)
		{
			var multiNodeData = new MultiNodeEditorData { SynchronizedSegments = new SourcePosition[0] };
			var terminal = executionContext.DocumentRepository.Statements.GetTerminalAtPosition(executionContext.CaretOffset, n => !String.Equals(n.Id, Terminals.Comma) && !String.Equals(n.Id, Terminals.Dot) && !String.Equals(n.Id, Terminals.RightParenthesis));
			if (executionContext.SelectionLength > 0 || terminal?.Id.IsIdentifierOrAlias() != true)
			{
				return multiNodeData;
			}

			multiNodeData.CurrentNode = terminal;

			var semanticModel = (OracleStatementSemanticModel)executionContext.DocumentRepository.ValidationModels[terminal.Statement].SemanticModel;

			OracleColumnReference columnReference;
			OracleQueryBlock cteQueryBlock;
			switch (terminal.Id)
			{
				case Terminals.ObjectAlias:
					var objectReference = semanticModel.AllReferenceContainers
						.SelectMany(c => c.ObjectReferences)
						.SingleOrDefault(o => o.AliasNode == terminal);

					var synchronizedSegments = new List<SourcePosition>();
					cteQueryBlock = semanticModel.QueryBlocks.SingleOrDefault(qb => qb.AliasNode == terminal);
					if (objectReference == null && cteQueryBlock != null)
					{
						synchronizedSegments.AddRange(GetDataObjectReferences(cteQueryBlock).Select(o => o.ObjectNode.SourcePosition));
					}

					var objectQualifiedColumnSynchronizedSegments = semanticModel.AllReferenceContainers
						.SelectMany(c => c.ColumnReferences)
						.Where(c => c.ObjectNode != null && c.ValidObjectReference != null && (c.ValidObjectReference == objectReference || IsCommonTableExpressionColumnReference(cteQueryBlock, c)))
						.Concat(GetCommonTableExpressionObjectPrefixedColumnReferences(cteQueryBlock))
						.Select(c => c.ObjectNode.SourcePosition);

					synchronizedSegments.AddRange(objectQualifiedColumnSynchronizedSegments);
					multiNodeData.SynchronizedSegments = synchronizedSegments.AsReadOnly();

					break;

				case Terminals.ObjectIdentifier:
					var editNodes = new List<SourcePosition>();

					columnReference = semanticModel.GetReference<OracleColumnReference>(terminal);

					var objectReferences = new HashSet<OracleDataObjectReference>();
					var dataObjectReferenceCandidate = columnReference?.ValidObjectReference as OracleDataObjectReference;
					if (dataObjectReferenceCandidate != null)
					{
						objectReferences.Add(dataObjectReferenceCandidate);
					}
					else
					{
						dataObjectReferenceCandidate = semanticModel.GetReference<OracleDataObjectReference>(terminal);
					}

					if (dataObjectReferenceCandidate?.Type == ReferenceType.CommonTableExpression)
					{
						objectReferences.Add(dataObjectReferenceCandidate);

						if (dataObjectReferenceCandidate.QueryBlocks.Count == 1)
						{
							cteQueryBlock = dataObjectReferenceCandidate.QueryBlocks.First();
							var cteColumnReferences = GetCommonTableExpressionObjectPrefixedColumnReferences(cteQueryBlock);
							editNodes.AddRange(cteColumnReferences.Select(c => c.ObjectNode.SourcePosition));
							editNodes.AddRange(GetDataObjectReferences(cteQueryBlock).Where(o => o != dataObjectReferenceCandidate).Select(o => o.ObjectNode.SourcePosition));

							StatementGrammarNode cteAliasNode;
							if (cteQueryBlock.AliasNode == null)
							{
								cteQueryBlock = cteQueryBlock.AllPrecedingConcatenatedQueryBlocks.Last();
								cteAliasNode = cteQueryBlock.AliasNode;
								var referencesToCte = semanticModel.AllReferenceContainers.SelectMany(c => c.ObjectReferences).Where(o => o.QueryBlocks.Count == 1 && o.QueryBlocks.First() == cteQueryBlock);
								objectReferences.UnionWith(referencesToCte);
							}
							else
							{
								cteAliasNode = cteQueryBlock.AliasNode;
							}

							editNodes.Add(cteAliasNode.SourcePosition);
						}
					}

					foreach (var dataObjectReference in objectReferences)
					{
						if (dataObjectReference.AliasNode != null && columnReference != null)
						{
							editNodes.Add(dataObjectReference.AliasNode.SourcePosition);
						}
						else if (dataObjectReference.Type == ReferenceType.CommonTableExpression && dataObjectReference.ObjectNode != terminal)
						{
							editNodes.Add(dataObjectReference.ObjectNode.SourcePosition);
						}

						if (dataObjectReference.AliasNode == null || columnReference != null)
						{
							var editNodesSource = semanticModel.AllReferenceContainers
								.SelectMany(c => c.ColumnReferences)
								.Where(r => r.ObjectNode != null && r != columnReference && r.ValidObjectReference == dataObjectReference)
								.Select(r => r.ObjectNode.SourcePosition);

							editNodes.AddRange(editNodesSource);
						}
					}

					multiNodeData.SynchronizedSegments = editNodes.AsReadOnly();
					break;

				case Terminals.BindVariableIdentifier:
					var bindVariable = FindUsagesCommand.GetBindVariable(semanticModel, terminal.Token.Value);
					multiNodeData.SynchronizedSegments = bindVariable.Nodes.Where(n => n != terminal).Select(t => t.SourcePosition).ToArray();
					break;

				case Terminals.ColumnAlias:
					var selectListColumn = semanticModel.AllReferenceContainers
						.OfType<OracleSelectListColumn>()
						.SingleOrDefault(c => c.AliasNode == terminal);

					if (selectListColumn != null)
					{
						multiNodeData.SynchronizedSegments = FindUsagesCommand.GetParentQueryBlockColumnUsages(selectListColumn)
							.TakeWhile(t => String.Equals(t.Token.Value.ToQuotedIdentifier(), selectListColumn.NormalizedName))
							.Select(t => t.SourcePosition)
							.ToArray();
					}
					else
					{
						goto case Terminals.Identifier;
					}

					break;

				case Terminals.Identifier:
					multiNodeData.SynchronizedSegments = FindUsagesCommand.GetColumnUsages(semanticModel, terminal, true)
						.Where(t => t != terminal)
						.Select(t => t.SourcePosition)
						.ToArray();
					break;
			}

			return multiNodeData;
		}